﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Algorithm.Check;
using Common;
using static Algorithm.Check.ExtensionForCRC16;

namespace NewDevice.RS485
{
    /// <summary>
    /// 数值显示格式枚举
    /// 对应下拉菜单中的各种数据显示格式选项
    /// </summary>
    public enum ZH_NumericDisplayFormat
    {
        /// <summary>
        /// 固定2位小数点 (默认选中项)
        /// </summary>
        [Description("固定2位小数点")]
        FixedTwoDecimal = 0,

        /// <summary>
        /// 浮动小数点
        /// </summary>
        [Description("浮动小数点")]
        FloatingDecimal,

        /// <summary>
        /// 固定3位小数点
        /// </summary>
        [Description("固定3位小数点")]
        FixedThreeDecimal,

        /// <summary>
        /// 固定4位小数点
        /// </summary>
        [Description("固定4位小数点")]
        FixedFourDecimal,

        /// <summary>
        /// 0~4095数字范围
        /// </summary>
        [Description("0~4095")]
        DigitalRange_0_4095,

        /// <summary>
        /// 电流浮点表示法
        /// </summary>
        [Description("电流浮点表示法")]
        CurrentFloatingPoint,

        /// <summary>
        /// 电流3位小数点表示法
        /// </summary>
        [Description("电流3位小数点表示法")]
        CurrentThreeDecimal,

        /// <summary>
        /// 电压浮点表示法
        /// </summary>
        [Description("电压浮点表示法")]
        VoltageFloatingPoint
    }

    /// <summary>
    /// 中盛模拟量采集卡
    /// </summary>
    public class ZS_AnalogInput
    {
        private SerialBase serial;
        private int slaveId;
        private string deviceName;
        private int channelCount;
        private ZH_NumericDisplayFormat dataFormat;

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="bus"></param>
        /// <param name="slaveId">从机地址</param>
        /// <param name="channelCount">通道数量</param>
        /// <param name="name"></param>
        /// <param name="format">数据解析方式</param>
        public ZS_AnalogInput(SerialBase bus, int slaveId, int channelCount, string name = "模拟量采集卡", ZH_NumericDisplayFormat format = ZH_NumericDisplayFormat.FixedThreeDecimal)
        {
            serial = bus;
            this.slaveId = slaveId;
            this.channelCount = channelCount;
            this.deviceName = name;
            this.dataFormat = format;
        }

        /// <summary>
        /// 读取数据
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        /// <exception cref="NotImplementedException"></exception>
        public List<double> GetValue()
        {
            byte[] data = new byte[] {
             (byte)slaveId,
             0x04, // 功能码
             0x00, 0x00, // 寄存器地址
             (byte)((channelCount & 0xff00) >> 8), // 高字节
             (byte)(channelCount & 0xff), // 低字节
            };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            serial.deviceName = deviceName;
            var recv = serial.SendBytesAndWaitResponse(cmd, ReceivedDataCheck.FuncModbusCRC16Check);
            if (recv.Length != channelCount * 2 + 3 + 2)
            {
                throw new Exception($"{deviceName}错误的返回数据");
            }

            List<short> tmp = recv.Skip(3) // 跳过前3个字节
                 .Take(channelCount * 2)    // 每个通道2个字节
                 .Select((b, i) => new { b, i })  // 带索引的投影
                 .GroupBy(x => x.i / 2)        // 每2个字节一组
                 .Where(g => g.Count() == 2)   // 确保每组有2字节
                 .Select(g => (short)((g.First().b << 8) | g.Last().b)) // 手动位移组合
                 .ToList();
            List<double> doubles = new List<double>();
            switch (dataFormat)
            {
                case ZH_NumericDisplayFormat.FixedTwoDecimal:
                    doubles = tmp.Select(x => x / 100.0).ToList();
                    break;

                case ZH_NumericDisplayFormat.FloatingDecimal:
                    doubles = tmp
                    .Select(x =>
                    {
                        int decimalPlaces = x / 10000;       // 提取万位（小数位数）
                        int numericValue = x % 10000;        // 提取数值部分
                        return numericValue / Math.Pow(10, decimalPlaces); // 计算最终值
                    })
                    .ToList();
                    break;

                case ZH_NumericDisplayFormat.FixedThreeDecimal:
                    doubles = tmp.Select(x => x / 1000.0).ToList();
                    break;

                case ZH_NumericDisplayFormat.FixedFourDecimal:
                    doubles = tmp.Select(x => x / 10000.0).ToList();
                    break;

                case ZH_NumericDisplayFormat.DigitalRange_0_4095:
                    throw new NotImplementedException();

                case ZH_NumericDisplayFormat.CurrentFloatingPoint:
                    throw new NotImplementedException();

                case ZH_NumericDisplayFormat.CurrentThreeDecimal:
                    throw new NotImplementedException();

                case ZH_NumericDisplayFormat.VoltageFloatingPoint:
                    throw new NotImplementedException();

                default:
                    throw new NotImplementedException();
            }
            return doubles;
        }
    }
}